package com.app.controller;


import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSONObject;
import com.app.model.AdminUserModel;
import com.app.model.MysqlModel;
import com.app.model.TestsModel;
import com.app.service.AdminUserService;
import com.app.service.MySqlService;
import com.app.util.Constants;
import com.app.util.Result;
import com.app.util.TokenUtils;
import com.app.vo.MySqlBackVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * Software：IntelliJ IDEA 2021.2 x64
 * Author: https://www.mobaijun.com
 * Date: 2021/9/16 14:45
 * ClassName:SystemMysqlBackupsController
 * 类描述： MySQL数据备份接口
 */
@RestController
@Slf4j
@Controller
@RequestMapping(value = "/api/system")
public class MysqlController {

    /**
     * 数据库用户名
     */
    @Value("${spring.datasource.username}")
    private String userName;

    /**
     * 数据库密码
     */
    @Value("${spring.datasource.password}")
    private String password;

    /**
     * 数据库url
     */

    @Value("${spring.datasource.url}")
    private String url ;

    /**
     * Windows数据库备份地址
     */
    @Value("${spring.windowsPath}")

    private String windowsPath ;

    /**
     * Linux数据库备份地址
     */

    private String linuxPath = "";


    @Autowired
    private MySqlService mySqlService;
    @Autowired
    private AdminUserService adminUserService;

    //"获取所有备份数据列表"
    @GetMapping("/backupsList")
    public Object backupsList() {
        List<MysqlModel> systemMysqlBackups = mySqlService.selectBackupsList();
        return systemMysqlBackups;
    }
    @GetMapping("/getBackupsList")
    public Object getBackupsList(
            @RequestParam("page") Integer page,
            @RequestParam("limit") Integer limit,
            @RequestParam(required = false) String backupsName,
            HttpServletRequest request
         ) {
        String token = request.getHeader("authori-zation");
        if (token == null) {
            return Result.error(405, "token不存在");
        }
        String userId = TokenUtils.verify(token);
        AdminUserModel user = adminUserService.getUserByUserId(Integer.parseInt(userId));
        if (user == null) {
            return Result.error(406, "用户不存在");
        }
        int GB = 1024 * 1024 * 1024;//定义GB的计算常量
        int MB = 1024 * 1024;//定义MB的计算常量
        int KB = 1024;//定义KB的计算常量
        DecimalFormat df = new DecimalFormat("0.00");//格式化小数
        String resultSize = "";

        Page<MysqlModel> systemMysqlBackups = mySqlService.getBackupsList(page,limit,backupsName);
        for (int i = 0; i < systemMysqlBackups.getRecords().size(); i++) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String crtTime = sdf.format(systemMysqlBackups.getRecords().get(i).getCreateTime());
            systemMysqlBackups.getRecords().get(i).setCreateTimeText(crtTime);
            if (Integer.parseInt(systemMysqlBackups.getRecords().get(i).getSize()) / GB >= 1) {
                //如果当前Byte的值大于等于1GB
                resultSize = df.format(Integer.parseInt(systemMysqlBackups.getRecords().get(i).getSize()) / (float) GB) + "GB";
            } else if (Integer.parseInt(systemMysqlBackups.getRecords().get(i).getSize()) / MB >= 1) {
                //如果当前Byte的值大于等于1MB
                resultSize = df.format(Integer.parseInt(systemMysqlBackups.getRecords().get(i).getSize()) / (float) MB) + "MB";
            } else if (Integer.parseInt(systemMysqlBackups.getRecords().get(i).getSize()) / KB >= 1) {
                //如果当前Byte的值大于等于1KB
                resultSize = df.format(Integer.parseInt(systemMysqlBackups.getRecords().get(i).getSize()) / (float) KB) + "KB";
            } else {
                resultSize = Integer.valueOf(systemMysqlBackups.getRecords().get(i).getSize()) + "B";
            }
            systemMysqlBackups.getRecords().get(i).setSizeText(resultSize);
        }
        int count = (int) systemMysqlBackups.getTotal();
        List<MysqlModel> mysqlModelList;
        mysqlModelList = systemMysqlBackups.getRecords();
        MySqlBackVo vo = new MySqlBackVo();
        vo.setCount(count);
        vo.setList(mysqlModelList);
        return Result.success(vo);
    }

    // "MySQL备份"
    @PostMapping("/mysqlBackups")
    public Object mysqlBackups() {
        String path = null;
        // 获取操作系统名称
        String osName = System.getProperty("os.name").toLowerCase();
        if (Constants.isSystem(osName)) {
            // Windows
            path = this.windowsPath;
        } else {
            // Linux
            path = this.linuxPath;
        }
        // 数据库用户名
        String userName = this.userName;
        System.out.println("第2次打印"+userName);

        // 数据库密码
        String password = this.password;
        System.out.println("第3次打印"+password);

        // 数据库地址
        String url = this.url;
        // 调用备份
        Object systemMysqlBackups = mySqlService.mysqlBackups(path, url, userName, password);

        return Result.success(null);
    }

    //"恢复数据库"
    @GetMapping("/rollback")
    public Object rollback(
            @RequestParam("id") Integer id,
            HttpServletRequest request
               ) {
        String token = request.getHeader("authori-zation");
        if (token == null) {
            return Result.error(405, "token不存在");
        }
        String userId = TokenUtils.verify(token);
        AdminUserModel user = adminUserService.getUserByUserId(Integer.parseInt(userId));
        if (user == null) {
            return Result.error(406, "用户不存在");
        }
        if (id == null) {
            return  HttpStatus.INTERNAL_SERVER_ERROR.value() + "id不能为null，请重新尝试！";
        }
        // 数据库用户名
        String userName = this.userName;
        // 数据库密码
        String password = this.password;
        // 根据id查询查询已有的信息
        MysqlModel smb = mySqlService.selectListId(Long.valueOf(id));
        // 恢复数据库
        Object rollback = mySqlService.rollback(smb, userName, password);
        // 更新操作次数
        mySqlService.updateById(smb);
        return Result.success(null);
    }
    @GetMapping("/deleteById")//删除单条备份数据
    public Result<Object> deleteById(
            @RequestParam("id") Integer id,
            HttpServletRequest request) {
        String token = request.getHeader("authori-zation");
        if (token == null) {
            return Result.error(405, "token不存在");
        }
        String userId = TokenUtils.verify(token);
        AdminUserModel user = adminUserService.getUserByUserId(Integer.parseInt(userId));
        if (user == null) {
            return Result.error(406, "用户不存在");
        }
        MysqlModel model = mySqlService.selectListId(Long.valueOf(id));
        if(model == null){
            return Result.error(500,"该条数据不存在");
        }else {
            mySqlService.delete(id);
            File file = new File(model.getBackupsPath()+model.getBackupsName());// 根据指定的文件名创建File对象
            if (!file.exists()) { // 要删除的文件不存在
                return Result.error(500,"文件" + model.getBackupsName() + "不存在，删除失败！");

            } else { // 要删除的文件存在
                if (file.isFile()) { // 如果目标文件是文件，判断是文件
                    log.info(file.delete()+"!!!");//删除文件
                    return Result.success(null);

                }
            }
        }
        return Result.success(null);
    }
    @PostMapping("/sqlDownload")
    public void sqlDownLoad(
            @RequestBody JSONObject json,
             HttpServletResponse response,
            HttpServletRequest request
    ) throws IOException {
        Integer id = Integer.valueOf(json.get("id").toString());
        // 根据id查询查询已有的信息
        MysqlModel smb = mySqlService.selectListId(Long.valueOf(id));
        File uploadFile=new File(smb.getBackupsPath()+smb.getBackupsName());
        ServletOutputStream os=response.getOutputStream();
        response.setContentType("application/x-msdownload");

        response.setHeader("content-disposition", "attachment;filename="+java.net.URLEncoder.encode(smb.getBackupsName()+".sql","UTF-8"));
        //读取文件字节流
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }
    @PostMapping("/zipFile")
    public void zipFile(
            @RequestBody JSONObject json,
//            @RequestParam Integer id,
            HttpServletResponse response
            ) throws IOException {
        Integer id = Integer.valueOf(json.get("id").toString());

        MysqlModel smb = mySqlService.selectListId(Long.valueOf(id));

        //这个是文件夹的绝对路径，如果想要相对路径就自行了解写法
        String sourceFile = smb.getBackupsPath()+smb.getBackupsName();
        //这个是压缩之后的文件绝对路径
        FileOutputStream fos = new FileOutputStream(
                smb.getBackupsPath()+smb.getBackupsName()+".zip");
        ZipOutputStream zipOut = new ZipOutputStream(fos);
        File fileToZip = new File(sourceFile);
        zipFile(fileToZip, fileToZip.getName(), zipOut);
        zipOut.close();
        fos.close();

        File uploadFile=new File(smb.getBackupsPath()+smb.getBackupsName()+".zip");
        ServletOutputStream os=response.getOutputStream();
        String outName = smb.getBackupsName().replace(".sql","");
        response.setHeader("content-disposition", "attachment;filename="+java.net.URLEncoder.encode(outName+".zip","UTF-8"));
        //读取文件字节流
        os.write(FileUtil.readBytes(uploadFile));
        os.flush();
        os.close();
    }

    private void zipFile(File fileToZip, String fileName, ZipOutputStream zipOut) throws IOException {
        if (fileToZip.isHidden()) {
            return;
        }
        if (fileToZip.isDirectory()) {
            if (fileName.endsWith("/")) {
                zipOut.putNextEntry(new ZipEntry(fileName));
                zipOut.closeEntry();
            } else {
                zipOut.putNextEntry(new ZipEntry(fileName + "/"));
                zipOut.closeEntry();
            }
            File[] children = fileToZip.listFiles();
            for (File childFile : children) {
                zipFile(childFile, fileName + "/" + childFile.getName(), zipOut);
            }
            return;
        }
        FileInputStream fis = new FileInputStream(fileToZip);
        ZipEntry zipEntry = new ZipEntry(fileName);
        zipOut.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
            zipOut.write(bytes, 0, length);
        }
        fis.close();
    }
}
